<template>
  <el-dialog
    v-model="visible"
    :title="dialogTitle"
    width="400px"
    :before-close="handleClose"
    destroy-on-close
    class="voice-call-dialog mobile-style"
    :close-on-click-modal="false"
    :show-close="false"
    :style="{ height: '700px !important' }"
  >
    <div class="call-wrapper">
      <!-- 顶部通话计时：仅在远端接通后显示（loading期间不显示） -->
      <div class="timer-bar" v-if="uiState === 'in_call' && remoteJoined">{{ callDurationText }}</div>
      <!-- 始终渲染 Jitsi 容器；音频模式下隐藏 iframe，仅保留音频连接 -->
      <div class="video-area" :class="{ audioOnly: !isVideo }">
        <div ref="jitsiContainer" class="jitsi-embed" :style="{ display: isVideo ? 'block' : 'none' }"></div>
        <!-- 本地已进房但远端未加入前展示加载遮罩 -->
        <div class="loading-overlay" v-if="showConnecting">
          <div class="spinner"></div>
          <div class="loading-text">正在建立连接...</div>
        </div>

        <div v-if="uiState === 'in_call' && !showConnecting && !isVideo" class="state-panel">
          <div class="state-title">通话中</div>
        </div>
      </div>

      <template v-if="uiState === 'dialing'">
        <div class="state-panel">
          <div class="state-title">拨打中...</div>
        </div>
      </template>
      <template v-else-if="uiState === 'ringing'">
        <div class="state-panel">
          <div class="state-title" v-if="props.callData?.isIncoming">
            来自 {{ props.callData?.senderName || '来电' }} 的通话
          </div>
          <div class="state-title" v-else>等待接听</div>
          <div class="state-sub">对方尚未接听</div>
        </div>
      </template>
      <!-- in_call 状态下显示底部控制区（视频区域已常驻） -->
      <!-- 统一底部操作区，始终渲染，根据状态显示不同按钮 -->
      <div class="bottom-actions" :class="{ 'in-call': uiState === 'in_call' }">
        <template v-if="uiState === 'in_call'">
          <!-- 通话接通后，仅保留挂断功能 -->
          <el-button class="circle-btn red" @click="hangup">
            <el-icon><Phone /></el-icon>
          </el-button>
        </template>
        <template v-else-if="uiState === 'ringing'">
          <template v-if="props.callData?.isIncoming">
            <el-button class="circle-btn red" @click="rejectIncoming">
              <el-icon><Phone /></el-icon>
            </el-button>
            <el-button class="circle-btn green" @click="acceptIncoming">
              <el-icon><Phone /></el-icon>
            </el-button>
          </template>
          <template v-else>
            <el-button class="circle-btn red" @click="hangup">
              <el-icon><Phone /></el-icon>
            </el-button>
          </template>
        </template>
        <template v-else-if="uiState === 'dialing'">
          <template v-if="!props.callData?.isIncoming">
            <el-button class="circle-btn red" @click="hangup">
              <el-icon><Phone /></el-icon>
            </el-button>
          </template>
        </template>
      </div>
    </div>


  </el-dialog>
</template>

<script setup>
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import { ElMessage } from 'element-plus'
import { getToken } from '@/utils/webStorage'
import wsClient, { MessageType } from '@/utils/websocket'
import { Phone, Microphone, VideoCamera } from '@element-plus/icons-vue'

// Props
const props = defineProps({
  visible: {
    type: Boolean,
    default: false
  },
  callData: {
    type: Object,
    default: () => ({})
  },
  baseUrl: {
    type: String,
    default: window.config_global.MEETING_BASE_URL || 'http://localhost:3000'
  }
})

// Emits
const emit = defineEmits(['update:visible', 'call-end'])

// Reactive data
const callingFrame = ref(null)
const loading = ref(true)
const callStatus = ref('connecting') // connecting, connected, ended
const isClosing = ref(false) // 防止重复关闭

// 新增：通话 UI 状态与媒体控制
// 根据身份初始化UI：来电方默认进入“等待接听”，外呼方为“拨打中”
const uiState = ref(props.callData?.isIncoming ? 'ringing' : 'dialing') // dialing, ringing, in_call
const isVideo = computed(() => !!props.callData?.isVideo)
const isAudioMuted = ref(false)
const isVideoMuted = ref(false)
const localVideoRef = ref(null)
const remoteVideoRef = ref(null)
const jitsiContainer = ref(null)
let jitsiApi = null
// 来电方接听标记：用于区分接听后应直接进入通话中
const incomingAccepted = ref(false)

// 通话计时（音频模式显示）
const callDurationText = ref('00:00')
let callTimer = null
let callStartAt = 0
function formatDuration(ms) {
  const total = Math.max(0, Math.floor(ms / 1000))
  const hh = Math.floor(total / 3600)
  const mm = Math.floor((total % 3600) / 60)
  const ss = total % 60
  if (hh > 0) {
    return `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}`
  }
  return `${String(mm).padStart(2, '0')}:${String(ss).padStart(2, '0')}`
}
function startCallTimer() {
  stopCallTimer()
  callStartAt = Date.now()
  callDurationText.value = '00:00'
  callTimer = setInterval(() => {
    callDurationText.value = formatDuration(Date.now() - callStartAt)
  }, 1000)
}
function stopCallTimer() {
  if (callTimer) {
    clearInterval(callTimer)
    callTimer = null
  }
}

// 加入状态与加载遮罩：接听后到双方都接通之间显示遮罩
const localJoined = ref(false)
const remoteJoined = ref(false)
const showConnecting = computed(() => {
  // 通话中且远端未加入时显示loading（包括刚接听但还未完全接通的阶段）
  return uiState.value === 'in_call' && !remoteJoined.value
})

// Jitsi 集成变量（旧 lib-jitsi-meet 将被替换为 External API）
let jitsiConnection = null
let jitsiConference = null
let localTracks = []
let remoteTracks = {}

// External API 配置与脚本加载
function getJitsiConfig() {
  const cfg = (window && window.config_global) || {}
  const domain = cfg.JITSI_DOMAIN || 'meet.jit.si'
  const externalApi = cfg.JITSI_EXTERNAL_API || `https://${domain}/external_api.js`
  return { domain, externalApi }
}

function loadJitsiScript(src) {
  return new Promise((resolve, reject) => {
    if (window.JitsiMeetExternalAPI) return resolve()
    const script = document.createElement('script')
    script.src = src
    script.async = true
    script.onload = () => resolve()
    script.onerror = (e) => reject(e)
    document.head.appendChild(script)
  })
}

// Computed
const visible = computed({
  get: () => props.visible,
  set: (value) => emit('update:visible', value)
})

const callingUrl = computed(() => {
  if (!props.callData || Object.keys(props.callData).length === 0) {
    return `${props.baseUrl}/calling`
  }

  const params = new URLSearchParams()

  // 添加通话参数
  if (props.callData.senderId) params.set('senderId', props.callData.senderId.toString())
  if (props.callData.receiverId) params.set('receiverId', props.callData.receiverId.toString())
  if (props.callData.receiverName) params.set('receiverName', props.callData.receiverName)
  if (props.callData.senderName) params.set('senderName', props.callData.senderName)
  if (props.callData.questionId) params.set('questionId', props.callData.questionId.toString())
  if (props.callData.recordId) params.set('recordId', props.callData.recordId.toString())

  // 添加通话类型参数
  params.set('isVideo', props.callData.isVideo ? '1' : '0')

  // 添加token参数
  const token = getToken()
  if (token) {
    params.set('token', token)
    params.set('authorization', token) // 兼容不同的token字段名
  }

  // 添加时间戳防止缓存
  params.set('timestamp', Date.now().toString())

  // 根据是否为来电决定路径
  const path = props.callData.isIncoming ? '/incoming' : '/calling'
  const url = `${props.baseUrl}${path}?${params.toString()}`
  console.log(`${props.callData.isVideo ? '视频' : '语音'}通话URL:`, url.replace(/([?&](?:token|authorization)=)[^&]+/g, '$1***TOKEN***'))
  return url
})

const dialogTitle = computed(() => {
  const callType = props.callData?.isVideo ? '视频' : '语音'
  if (props.callData?.isIncoming) {
    const senderName = props.callData?.senderName || '专家'
    return `来自 ${senderName} 的${callType}通话`
  } else {
    const receiverName = props.callData?.receiverName || '专家'
    return `与 ${receiverName} 的${callType}通话`
  }
})



// Methods
// 生成房间名（双方一致即可加入同一房间）
const roomName = computed(() => {
  const base = props.callData?.questionId || props.callData?.recordId || 'room'
  const a = props.callData?.senderId || 's'
  const b = props.callData?.receiverId || 'r'
  return `vc-${base}-${a}-${b}`
})

async function initAndJoinConference() {
  try {
    loading.value = true
    localJoined.value = false
    remoteJoined.value = false
    // 仅在外呼或未接听来电时显示拨打中
    if (uiState.value !== 'in_call') {
      uiState.value = 'dialing'
    }

    // 使用 Jitsi External API 初始化
    const { domain, externalApi } = getJitsiConfig()
    await loadJitsiScript(externalApi)
    await nextTick()
    if (!jitsiContainer.value) return

    // 若已有实例，先释放
    if (jitsiApi && jitsiApi.dispose) {
      try { jitsiApi.dispose() } catch {}
      jitsiApi = null
    }

    const displayName = (props.callData?.isIncoming ? props.callData?.receiverName : props.callData?.senderName) || '用户'
    jitsiApi = new window.JitsiMeetExternalAPI(domain, {
      roomName: roomName.value,
      parentNode: jitsiContainer.value,
      width: '100%',
      height: '100%',
      lang: 'zh-CN',
      userInfo: { displayName },
      configOverwrite: {
        prejoinPageEnabled: false,
        enableWelcomePage: false,
        startWithAudioMuted: false,
        startWithVideoMuted: !isVideo.value,
        disableDeepLinking: true,
        enableClosePage: false,
      },
      interfaceConfigOverwrite: {
        // 通话内仅保留我们自定义的挂断按钮，隐藏 Jitsi 自带工具栏
        TOOLBAR_BUTTONS: [],
      }
    })

    jitsiApi.addEventListener('videoConferenceJoined', () => {
      callStatus.value = 'connected'
      loading.value = false
      localJoined.value = true
      // 不覆盖已进入通话中的状态（发起方收到同意后应保持 in_call 展示 loading）
      if (uiState.value !== 'in_call') {
        uiState.value = incomingAccepted.value ? 'in_call' : 'ringing'
      }
    })
    jitsiApi.addEventListener('participantJoined', () => {
      remoteJoined.value = true
      uiState.value = 'in_call'
      startCallTimer()
    })
    jitsiApi.addEventListener('readyToClose', () => {
      if (!isClosing.value) handleClose()
    })
  } catch (e) {
    console.error('Jitsi 初始化失败:', e)
    uiState.value = 'dialing'
  }
}

function hangup() {
  try {
    if (jitsiApi && typeof jitsiApi.executeCommand === 'function') {
      jitsiApi.executeCommand('hangup')
    } else {
      try { jitsiConference?.leave() } catch {}
      try { jitsiConnection?.disconnect() } catch {}
      try { jitsiApi?.dispose() } catch {}
    }
  } catch {}
  stopCallTimer()
  localJoined.value = false
  remoteJoined.value = false
  wsClient.send(MessageType.CALL_END, {
    senderId: props.callData.senderId,
    receiverId: props.callData.receiverId,
    questionId: props.callData.questionId,
    recordId: props.callData?.recordId,
    timestamp: Date.now(),
  })
  handleClose()
}

function acceptIncoming() {
  // 标记已接听，并立即切换到通话中 UI
  incomingAccepted.value = true
  uiState.value = 'in_call'

  wsClient.send(MessageType.CALL_AGREE, {
    senderId: props.callData.senderId,
    receiverId: props.callData.receiverId,
    questionId: props.callData.questionId,
    timestamp: Date.now(),
  })
  initAndJoinConference()
}

function rejectIncoming() {
  wsClient.send(MessageType.CALL_REJECT, {
    senderId: props.callData.senderId,
    receiverId: props.callData.receiverId,
    questionId: props.callData.questionId,
    recordId: props.callData?.recordId,
    timestamp: Date.now(),
    reason: '用户拒绝'
  })
  setTimeout(() => handleClose(), 500)
}
const handleClose = () => {
  // 防止重复关闭
  if (isClosing.value) {
    return
  }
  isClosing.value = true

  callStatus.value = 'ended'
  visible.value = false
  emit('call-end', {
    callData: props.callData,
    duration: Date.now() - (props.callData.startTime || Date.now())
  })
  stopCallTimer()
  // 确保释放并置空Jitsi实例，避免下次拨打被判定已存在
  try { jitsiApi?.dispose?.() } catch {}
  jitsiApi = null
  try { jitsiConference?.leave?.() } catch {}
  try { jitsiConnection?.disconnect?.() } catch {}
  localJoined.value = false
  remoteJoined.value = false
}

// Watch
watch(() => props.visible, (newVisible) => {
  if (newVisible) {
    isClosing.value = false // 重置关闭状态
    callStatus.value = 'connecting'
    // 重置计时器和加入状态
    stopCallTimer()
    callDurationText.value = '00:00'
    localJoined.value = false
    remoteJoined.value = false
    console.log('语音通话弹窗打开，通话数据:', props.callData)
    // 来电：显示"等待接听"；外呼：显示"拨打中"并立即初始化 Jitsi
    if (props.callData?.isIncoming) {
      uiState.value = 'ringing'
    } else {
      uiState.value = 'dialing'
      // 发起方不再在弹窗打开时初始化，等待对方同意后再初始化
    }
  }
})

watch(() => props.callData, (newData) => {
  if (newData && Object.keys(newData).length > 0) {
    console.log('通话数据更新:', newData)
    // 来电：始终保持“等待接听”；发起方：不要在已经通话中时回退为“拨打中”
    if (newData.isIncoming) {
      uiState.value = 'ringing'
    } else {
      if (uiState.value !== 'in_call') {
        uiState.value = 'dialing'
        // 发起方不在数据更新时初始化，改为在对方同意后初始化
      }
    }
  }
})

// WebSocket消息处理函数
const handleCallAgreeMessage = (data) => {
  console.log('收到通话同意消息:', data)
  // 对方接受后，发起方立即切换为通话中，避免仍显示“拨打中/等待接听”
  uiState.value = 'in_call'
  // 若我是发起方，则在对方同意后再初始化 Jitsi
  if (!props.callData?.isIncoming) {
    // 重置加入状态与计时显示，开始“接通中”的loading
    localJoined.value = false
    remoteJoined.value = false
    stopCallTimer()
    callDurationText.value = '00:00'
    // 无条件初始化；内部会在存在实例时先行dispose
    initAndJoinConference()
  }
}

const handleCallRejectMessage = (data) => {
  console.log('收到通话拒绝消息:', data)
  const reason = data.reason || '对方拒绝了通话'

  // 通话结束后关闭弹窗
  setTimeout(() => {
    if (!isClosing.value) {
      handleClose()
    }
  }, 1000)
}

const handleCallEndMessage = (data) => {
  console.log('收到通话结束消息:', data)
  const duration = data.duration ? ` (通话时长: ${Math.round(data.duration / 1000)}秒)` : ''

  // 通话结束后关闭弹窗
  setTimeout(() => {
    if (!isClosing.value) {
      handleClose()
    }
  }, 1000)
}

// Lifecycle
onMounted(() => {
  // 注册WebSocket消息监听器
  wsClient.on(MessageType.CALL_AGREE, handleCallAgreeMessage)
  wsClient.on(MessageType.CALL_REJECT, handleCallRejectMessage)
  wsClient.on(MessageType.CALL_END, handleCallEndMessage)

  // 若为外呼，直接初始化并加入会议；来电则等待用户操作
  if (!props.callData?.isIncoming) {
    // 外呼场景：不再立即初始化，等待对方同意
    uiState.value = 'dialing'
  } else {
    uiState.value = 'ringing'
  }
})

onUnmounted(() => {
  // 移除WebSocket消息监听器
  wsClient.off(MessageType.CALL_AGREE, handleCallAgreeMessage)
  wsClient.off(MessageType.CALL_REJECT, handleCallRejectMessage)
  wsClient.off(MessageType.CALL_END, handleCallEndMessage)

  try { jitsiApi?.dispose?.() } catch {}
  try { jitsiConference?.leave(); } catch {}
  try { jitsiConnection?.disconnect(); } catch {}
  stopCallTimer()
  localJoined.value = false
  remoteJoined.value = false
})
</script>

<style scoped>
.voice-call-dialog.mobile-style :deep(.el-dialog) {
  height: 700px !important;
  max-height: 700px !important;
  min-height: 700px !important;
  width: 400px !important;
  display: flex !important;
  flex-direction: column !important;
  border-radius: 20px;
  overflow: hidden;
  margin: auto !important;
}

.voice-call-dialog.mobile-style :deep(.el-dialog__header) {
  padding: 12px 20px;
  background: #f8f9fa;
  border-bottom: 1px solid #eee;
  flex-shrink: 0;
  height: 60px;
  box-sizing: border-box;
}

.voice-call-dialog.mobile-style :deep(.el-dialog__title) {
  font-size: 16px;
  font-weight: 500;
  text-align: center;
}

.voice-call-dialog.mobile-style :deep(.el-dialog__body) {
  flex: 1 !important;
  padding: 0 !important;
  display: flex !important;
  flex-direction: column !important;
  height: 640px !important;
  max-height: 640px !important;
  min-height: 640px !important;
}

.call-wrapper {
  flex: 1 !important;
  position: relative;
  width: 100% !important;
  height: 100% !important;
  min-height: 640px !important;
  background: #fff;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  padding-bottom: 12px;
}

.timer-bar {
  position: absolute;
  top: 12px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 4;
  /* 去掉背景，仅显示文本 */
  background: transparent;
  /* 文本颜色使用原背景色（深色半透明），与当前白色背景协调 */
  color: rgba(0,0,0,0.6);
  padding: 0;
  border-radius: 0;
  font-size: 14px;
}

.state-panel {
  color: #111;
  text-align: center;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  z-index: 2;
}
.state-title { font-size: 18px; margin-bottom: 8px; }
.state-sub { font-size: 14px; color: #bbb; }
.actions { margin-top: 16px; display: flex; gap: 12px; justify-content: center; }

/* 底部圆形图标按钮，仿微信样式 */
.bottom-actions {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 56px;
  display: flex;
  gap: 20px;
  align-items: center;
  z-index: 3;
}
/* .bottom-actions.in-call { bottom: 20px; } */

.circle-btn {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 12px rgba(0,0,0,0.25);
  border: none;
  padding: 0 !important;
  min-width: 64px;
  aspect-ratio: 1 / 1;
  box-sizing: border-box;
}
.circle-btn :deep(.el-icon) { font-size: 26px; }
.circle-btn.green { background: #1aad19; color: #fff; }
.circle-btn.red { background: #ff3b30; color: #fff; }
.circle-btn.gray { background: #2c2c2e; color: #fff; }
.circle-btn.off { opacity: 0.6; }

.video-area {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  background: #fff;
  z-index: 1;
}
.video-area.audioOnly { align-items: center; justify-content: center; }
.video-pane { flex: 1; position: relative; }
.video-pane.local { position: absolute; right: 12px; bottom: 12px; width: 160px; height: 120px; border: 2px solid #444; border-radius: 8px; overflow: hidden; }
.video-el { width: 100%; height: 100%; object-fit: cover; background: #fff; }
.jitsi-embed { width: 100%; height: 100%; }
/* 旧控件样式已弃用 */

/* 加载遮罩 */
.loading-overlay {
  position: absolute;
  left: 0; right: 0; top: 0; bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: rgba(255,255,255,0.85);
  z-index: 3;
}
.spinner {
  width: 36px;
  height: 36px;
  border: 3px solid #ddd;
  border-top-color: #409eff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
  margin-bottom: 8px;
}
.loading-text { color: #666; font-size: 14px; }
@keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

/* 响应式设计 */
@media (max-width: 768px) {
  .voice-call-dialog.mobile-style :deep(.el-dialog) {
    height: 100vh;
    width: 100vw !important;
    margin: 0;
    border-radius: 0;
    top: 0 !important;
    left: 0 !important;
    transform: none !important;
  }

  .voice-call-dialog.mobile-style :deep(.el-dialog__body) {
    height: calc(100% - 60px);
  }
}
</style>

<style>
/* 全局样式，确保弹窗高度生效 */
.voice-call-dialog.mobile-style .el-dialog {
  height: 700px !important;
  max-height: 700px !important;
  min-height: 700px !important;
}

.voice-call-dialog.mobile-style .el-dialog__body {
  height: 640px !important;
  max-height: 640px !important;
  min-height: 640px !important;
}
</style>
